package com.mc.fastkit.utils

import android.Manifest
import android.content.ContentValues
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.mc.fastkit.ext.app
import com.mc.fastkit.ext.realPath
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.OutputStream

/**
 * 图片格式工具类
 * @author: MasterChan
 * @date: 2023-12-25 13:54
 */
object ImageUtils {

    fun isJPG(bitmap: Bitmap): Boolean {
        return !bitmap.hasAlpha()
    }

    fun isJPG(path: String): Boolean {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(path, options)
        return options.outMimeType != null && options.outMimeType == "image/jpeg"
    }

    fun isPNG(bitmap: Bitmap): Boolean {
        return bitmap.hasAlpha()
    }

    fun isPNG(path: String): Boolean {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(path, options)
        return options.outMimeType != null && options.outMimeType == "image/png"
    }

    fun isWebP(bitmap: Bitmap): Boolean {
        return bitmap.byteCount % 4 == 0
    }

    fun isWebP(path: String): Boolean {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(path, options)
        return options.outWidth % 4 == 0 && options.outHeight % 4 == 0
    }

    fun getInSampleSize(options: BitmapFactory.Options, maxWidth: Int, maxHeight: Int): Int {
        var height = options.outHeight
        var width = options.outWidth
        var inSampleSize = 1
        while (height > maxHeight || width > maxWidth) {
            height = height shr 1
            width = width shr 1
            inSampleSize = inSampleSize shl 1
        }
        return inSampleSize
    }

    fun getBitmap(filePath: String?, maxWidth: Int, maxHeight: Int): Bitmap? {
        if (filePath.isNullOrEmpty()) {
            return null
        }
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(filePath, options)
        options.inSampleSize = getInSampleSize(options, maxWidth, maxHeight)
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeFile(filePath, options)
    }

    fun getBitmap(@DrawableRes res: Int, maxWidth: Int, maxHeight: Int): Bitmap? {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(app.resources, res, options)
        options.inSampleSize = getInSampleSize(options, maxWidth, maxHeight)
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeResource(app.resources, res, options)
    }

    fun getBitmap(data: ByteArray, offset: Int, maxWidth: Int, maxHeight: Int): Bitmap? {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeByteArray(data, offset, data.size, options)
        options.inSampleSize = getInSampleSize(options, maxWidth, maxHeight)
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeByteArray(data, offset, data.size, options)
    }

    fun save2Album(
        bitmap: Bitmap,
        dirName: String? = null,
        fileName: String? = null,
        format: CompressFormat = CompressFormat.PNG,
        quality: Int = 100
    ): File? {
        val safeDirName = if (dirName.isNullOrEmpty()) app.packageName else dirName
        val suffix = if (CompressFormat.JPEG == format) "JPG" else format.name
        val saveName = fileName ?: "${System.currentTimeMillis()}_$quality.$suffix"
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            val permissionState = ContextCompat.checkSelfPermission(
                app, Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
            if (permissionState != PackageManager.PERMISSION_GRANTED) {
                return null
            }
            val picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
            val destFile = File(picDir, "$safeDirName/$saveName")

            val bos = ByteArrayOutputStream()
            bitmap.compress(format, quality, bos)
            destFile.writeBytes(bos.toByteArray())

            val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
            intent.setData(Uri.parse("file://" + destFile.absolutePath))
            app.sendBroadcast(intent)

            destFile
        } else {
            val contentValues = ContentValues()
            contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, saveName)
            contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*")
            val contentUri = if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            } else {
                MediaStore.Images.Media.INTERNAL_CONTENT_URI
            }
            contentValues.put(
                MediaStore.Images.Media.RELATIVE_PATH,
                Environment.DIRECTORY_DCIM + "/" + safeDirName
            )
            contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1)
            val uri = app.contentResolver.insert(contentUri, contentValues) ?: return null
            var os: OutputStream? = null
            try {
                os = app.contentResolver.openOutputStream(uri)
                bitmap.compress(format, quality, os!!)
                contentValues.clear()
                contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
                app.contentResolver.update(uri, contentValues, null, null)
                if (uri.realPath == null) null else File(uri.realPath!!)
            } catch (e: Exception) {
                app.contentResolver.delete(uri, null, null)
                e.printStackTrace()
                null
            } finally {
                try {
                    os?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }
}